﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace Weazel.Willows.PreliminaryModel
{
	public class Connector 
		: TypedItem
	{
		private ConnectorKind kind;
		public ConnectorKind Kind
		{
			get { return kind; }
		}

		private ConnectorDirection direction;
		public ConnectorDirection Direction
		{
			get { return direction; }
		}

		public Connector(
			Model model, 	
			IdentifierMap identiferMap,
			List<ModelError> errors, 
			XmlElement description
		)
			: base(model)
		{
			read(identiferMap, errors, description);
		}

		#region Read from XML
		private void readKind(List<ModelError> errors, XmlElement description)
		{
			string value = description.Attributes["kind"].Value.ToLower();

			this.kind =
				value == "port" ? ConnectorKind.Port :
				value == "queue" ? ConnectorKind.Queue :
				ConnectorKind.Unknown;

			if (kind == ConnectorKind.Unknown)
			{
				string message =
					String.Format(
						"Unknown connector kind '{0}'",
						description.Attributes["kind"].Value
					);

				errors.Add(new ModelError(message));
			}
		}

		private void readDirection(List<ModelError> errors, XmlElement description)
		{
			string value = description.Attributes["direction"].Value.ToLower();

			// get direction 
			direction =
				value == "in" ? ConnectorDirection.In :
				value == "out" ? ConnectorDirection.Out :
				ConnectorDirection.Unknown;

			if (direction == ConnectorDirection.Unknown)
			{
				string message =
					String.Format(
						"Unknown Connector Direction '{0}'",
						description.Attributes["direction"].Value
					);

				errors.Add(new ModelError(message));
			}
		}

		private void read(IdentifierMap identiferMap, List<ModelError> errors, XmlElement description)
		{
			System.Diagnostics.Debug.Assert(description.HasAttribute("name"));
			System.Diagnostics.Debug.Assert(description.HasAttribute("kind"));
			System.Diagnostics.Debug.Assert(description.HasAttribute("direction"));

			this.Name = description.Attributes["name"].Value;

			readKind(errors, description);
			readDirection(errors, description);

			ReadType(description);

			identiferMap.Add(Name, this);
		}
		#endregion

		public void ExpandTo(Weazel.Willows.Model.Module module, HierarchicalName hierarchicalName)
		{
			System.Diagnostics.Trace.Assert(Type != null);

			string uniqueName = 
				hierarchicalName.CreateUniqueName(this.Name);

			switch (kind)
			{
				case ConnectorKind.Queue:
					{
						if (direction == ConnectorDirection.In)
						{
							Weazel.Willows.Model.QueueConnectorReaderInterface reader =
								new Weazel.Willows.Model.QueueConnectorReaderInterface(
									module,
									Model.TypeRegistry, 
									Type, 
									Name, 
									uniqueName
								);

							module.Connectors.Add(Name, reader);
						}
						else if (direction == ConnectorDirection.Out)
						{
							Weazel.Willows.Model.QueueConnectorWriterInterface writer =
								new Weazel.Willows.Model.QueueConnectorWriterInterface(
									module,
									Model.TypeRegistry,
									Type,
									Name,
									uniqueName
								);

							module.Connectors.Add(Name, writer);
						}
						else
						{
							throw new NotSupportedException();
						}
						break;
					}
				case ConnectorKind.Port:
					{
						if (direction == ConnectorDirection.In)
						{
							Weazel.Willows.Model.SignalInConnector reader =
								new Weazel.Willows.Model.SignalInConnector(
									module,
									Model.TypeRegistry,
									Type,
									Name,
									uniqueName
								);

							module.Connectors.Add(Name, reader);
						}
						else if (direction == ConnectorDirection.Out)
						{
							Weazel.Willows.Model.SignalOutConnector reader =
								new Weazel.Willows.Model.SignalOutConnector(
									module,
									Model.TypeRegistry,
									Type,
									Name,
									uniqueName
								);

							module.Connectors.Add(Name, reader);
						}
						else
						{
							throw new NotSupportedException();
						}
						break;
					}
				default:
					throw new NotSupportedException();
			}
		}

		public override string ToString()
		{
			return string.Format("Connector '{0}' kind '{1}' direction '{2}'", Name, kind, direction);
		}
	}
}
